/**
 * @file CRhoBrentPvmAlg.cpp Implementácia triedy CRhoBrentPvmAlg.
 *
 * @author Martin Kosorinský.
 * @date 10.10.2009.
 */

#include "CRhoBrentPvmAlg.hpp"

int CRhoBrentPvmAlg::pTID = -1;

bool CRhoBrentPvmAlg::computeLogarithm(int ptid, int dist, big vysledok) {

    tracer << "Spusteny Brentov Pollard-Rho algoritmus (PVM)" << endl;
    if (!isInitialized()) {
        cerr << "Error: '" << __FUNCTION__ << "': Nie je inicializovaný kontext!" << endl;
        exit(EXIT_FAILURE); // ukoncujeme program, aby sme zabranili zacykleniu
    }

    bool retVal = false;
    pTID = ptid;

    epoint *Z = epoint_init();
    epoint *W = epoint_init();

    big ai = mirvar(1);
    big aj = mirvar(1);
    big bi = mirvar(0);
    big bj = mirvar(0);

    big i = mirvar(1);
    big l = mirvar(1);
    big tmp1 = mirvar(0);
    big distMod = mirvar(1);

    bigrand(ord, ai);
    bigrand(ord, bi);
    copy(bi, bj);
    copy(ai, aj);

    sftbit(distMod, dist, distMod);

    tracer << "ptid=t" << hex << ptid << dec << ", dist=" << dist << endl;

    ecurve_mult2(ai, G, bi, H, Z);
    epoint_copy(Z, W);

    tracer << "Domain point: " << G << endl;
    tracer << "Task point: " << H << endl;
    tracer << "Starting point: "  << Z << endl;

    while (true) {
        makeStep(W, ai, bi, bigBuffer[0]);
        if (isDistinguished(W, ai, bi, distMod)) {
            // nasli sme distinguished bod, ukoncujeme algoritmus bez najdenia DL
            retVal = false;
            break;
        }
        incr(i, 1, i);
        if (epoint_comp(W, Z)) {
            if (computeIndex(ai, bi, aj, bj, vysledok)) {
                retVal = true;
                break;
            }
        }

        copy(l, tmp1);
        sftbit(tmp1, 1, tmp1); // tmp1 = 2*tmp1
        if (compare(i, tmp1) != -1) {
            epoint_copy(W, Z);
            copy(ai, aj);
            copy(bi, bj);
            sftbit(l, 1, l); // l = 2*l
        }
    }
    mirkill(ai);
    mirkill(aj);
    mirkill(bi);
    mirkill(bj);
    mirkill(i);
    mirkill(l);
    mirkill(tmp1);
    mirkill(distMod);
    epoint_free(W);
    epoint_free(Z);
    return retVal;
}

bool CRhoBrentPvmAlg::isDistinguished(epoint * X, big a, big b, big distMod) {

    bool retVal = false;
    if (!point_at_infinity(X)) {
        epoint_get(X, bigBuffer[0], bigBuffer[1]);

        if (divisible(bigBuffer[1], distMod)) {
            pvmSendDistPoint(pTID, X, a, b);
            retVal = true;
        }
    }
    return retVal;
}
